#pragma once
#include <memory>
#include <mutex>
#include <iostream>

template <typename T>
class Singleton {
protected:
    Singleton() = default;

    static std::shared_ptr<T> _instance;

public:
    Singleton(const Singleton&) = delete;

    Singleton& operator=(const Singleton&) = delete;

    template <typename... Args>
    static std::shared_ptr<T> GetInstance(Args&&... args) {
        static std::once_flag s_flag;
        std::call_once(s_flag, [&]() {
            _instance = std::shared_ptr<T>(new T(std::forward<Args>(args)...));
        });
        return _instance;
    }

    ~Singleton() = default;
};

template <typename T>
std::shared_ptr<T> Singleton<T>::_instance = nullptr;
